package com.xiaofengstu.mcams.util;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author FengZeng
 * @Date 2022-05-13 22:43
 * @Description Redis序列化工具
 */
@Slf4j
public class SerializeUtils<T> {

  /**
   * 序列化对象
   *
   * @param object
   * @return
   */
  public byte[] serialize(Object object) {
    ObjectOutputStream oos = null;
    ByteArrayOutputStream baos = null;
    byte[] bytes = null;
    try {
      // 序列化
      baos = new ByteArrayOutputStream();
      oos = new ObjectOutputStream(baos);
      oos.writeObject(object);
      bytes = baos.toByteArray();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      try {
        if (oos != null) {
          oos.close();
        }
        if (baos != null) {
          baos.close();
        }
      } catch (Exception e2) {
        e2.printStackTrace();
      }
    }
    return bytes;
  }

  /**
   * 反序列化对象
   *
   * @param bytes
   * @return
   */
  public Object unSerialize(byte[] bytes) {
    Object obj = null;
    ByteArrayInputStream bais = null;
    try {
      // 反序列化
      bais = new ByteArrayInputStream(bytes);
      ObjectInputStream ois = new ObjectInputStream(bais);
      obj = ois.readObject();
      ois.close();
      bais.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return obj;
  }

  /**
   * 关闭的数据源或目标。调用 close()方法可释放对象保存的资源（如打开文件）
   * 关闭此流并释放与此流关联的所有系统资源。如果已经关闭该流，则调用此方法无效。
   *
   * @param closeable
   */
  public void close(Closeable closeable) {
    if (closeable != null) {
      try {
        closeable.close();
      } catch (Exception e) {
        log.info("Unable to close {}", closeable, e);
      }
    }
  }

  /**
   * 列表序列化（用于Redis整存整取）
   *
   * @param value
   * @return
   */
  public <T> byte[] serialize(List<T> value) {
    if (value == null) {
      throw new NullPointerException("Can't serialize null");
    }
    byte[] rv = null;
    ByteArrayOutputStream bos = null;
    ObjectOutputStream os = null;
    try {
      bos = new ByteArrayOutputStream();
      os = new ObjectOutputStream(bos);
      for (T obj : value) {
        os.writeObject(obj);
      }
      os.writeObject(null);
      os.close();
      bos.close();
      rv = bos.toByteArray();
    } catch (IOException e) {
      throw new IllegalArgumentException("Non-serializable object", e);
    } finally {
      close(os);
      close(bos);
    }
    return rv;
  }

  /**
   * 反序列化列表（用于Redis整存整取）
   *
   * @param in
   * @return
   */
  public <T> List<T> unSerializeForList(byte[] in) {
    List<T> list = new ArrayList<>();
    ByteArrayInputStream bis = null;
    ObjectInputStream is = null;
    try {
      if (in != null) {
        bis = new ByteArrayInputStream(in);
        is = new ObjectInputStream(bis);
        while (true) {
          T obj = (T) is.readObject();
          if (obj == null) {
            break;
          } else {
            list.add(obj);
          }
        }
        is.close();
        bis.close();
      }
    } catch (IOException e) {
      log.warn("Caught IOException decoding %d bytes of data,{}",
          in.length, e);
    } catch (ClassNotFoundException e) {
      log.warn("Caught CNFE decoding %d bytes of data,{}",
          in.length, e);
    } finally {
      close(is);
      close(bis);
    }
    return list;
  }

}

